package demo1;

//在面向对象的概念中，所有的对象都是通过类来描述的，但不是所有的类都是用来描述对象的
//比如多态中的例子，Shape类虽然有draw方法，但并没有实际工作绘制图形是由Shape的子类来完成的
//像这种没有实际工作的方法，就把它设计为一个抽象方法，包含抽象方法的类成为抽象类

abstract class Shape {
    //如果一个方法不想有具体的实现，就可以把该方法设计为抽象方法
	public abstract void draw();
}
class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("圆");
    }
}
class Rectangle extends Shape {
    @Override
    public void draw() {
        System.out.println("矩形");
    }
}
class Flower extends Shape {
    @Override
    public void draw() {
        System.out.println("❀");
    }
}
public class AbstractClass_note {
    public static void drawMap(Shape shape) {
        shape.draw();
    }
    public static void main(String[] args) {
        drawMap(new Circle());
        drawMap(new Rectangle());
        //new Circle() 这个叫做匿名对象
        //缺点是每次使用都要实例化一个对象
        //new Circle().draw();
        //new Circle().draw(); 如果要画两个圆，用匿名对象只能这么写。
    }
}
//总结：
//1. 抽象类是被abstract修饰的
//2. 被abstract修饰的方法是抽象方法，没有具体的实现，子类必须重写该方法
//3. 当一个类中有抽象方法，那么这个类必须被abstract修饰
//4. 抽象类中可以有和普通类一样的普通方法和属性，甚至构造方法
//5. 抽象类是不能被实例化的
//6. 既然不能实例化，要抽象类就是为了被继承
//7. 当一个普通类继承了这个抽象类之后，这个普通类必须重写抽象类中的所有抽象方法
//8. final和abstract不能同时存在，抽象方法不能被final和static修饰
//9. 抽象方法的构造方法就是用来让子类调用，帮助这个抽象类初始化自己的成员
//10.当一个类A不想被普通类B继承，那就可以把B变成抽象类，当一个普通类C继承了抽象类B后，C要继承A，B中所有的抽象方法。
//11.抽象类中不一样有抽象方法，有抽象方法的类一定是抽象类

//相较于普通类，使用抽象类就是多加了一重编译器的校验。可以看到子类若没有重写，会报错。
//使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了,
// 使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题.
//很多语法存在的意义都是为了 "预防出错", 例如我们曾经用过的 ﬁnal 也是类似. 创建的变量用户不去修改,
// 不就相当于常量嘛? 但是加上 ﬁnal 能够在不小心误修改的时候, 让编译器及时提醒我们.
//充分利用编译器的校验, 在实际开发中是非常有意义的.